Infinite Web Game Engine Architecture

A comprehensive guide to building a modular, data-driven 2D game engine designed for infinite, chunk-based worlds using HTML5, JavaScript, React, and PixiJS.

1. Overview & Separation of Concerns

To keep the engine scalable and highly modular, the architecture relies on strict separation between three core pillars:

2. Tech Stack

The chosen technologies leverage the speed of WebGL and the dynamic nature of JavaScript:

3. Entity-Component-System (ECS) & Memory

To avoid JavaScript Garbage Collection (GC) stutters, the engine uses a Data-Oriented Design.

4. Infinite World & Chunk Management

The world is based on a 32x32 infinite grid. Because you cannot hold an infinite world in memory, data is dynamically loaded and unloaded.

Chunk Storage Map

World data is stored in a JavaScript Map using a string coordinate hash as the key. This allows the world to expand infinitely in any direction, including negative coordinates.

// Example hash key format: "chunkX,chunkY" -> "-1,4"
const chunkMap = new Map();

function getChunkKey(worldX, worldY) {
    const chunkX = Math.floor(worldX / (32 * 32));
    const chunkY = Math.floor(worldY / (32 * 32));
    return `${chunkX},${chunkY}`;
}

Rendering Object Pool

To maintain performance, PixiJS objects are never created or destroyed on the fly. The engine uses an Object Pool.

  1. Pre-allocate enough Pixi Container objects to cover the screen plus a buffer.
  2. When a chunk leaves the screen, clear its children, return the container to the pool, and save its raw tile data to the chunkMap.
  3. When a new chunk enters, grab an idle container from the pool and populate it with sprites.

5. The "Pop-In" Plugin System

Libraries (like procedural generation or specialized AI) can simply be dropped into a folder and instantly recognized.

This is achieved using native ES Dynamic Imports. Plugins hook into the engine's Event Bus and chunk lifecycles.

Example: Procedural Generation Hook

// plugins/BiomeGenerator.js
export const plugin = {
    id: "procedural-biomes",
    init(engine) {
        // Hook into the core engine's chunk creation event
        engine.chunks.on('chunk_created', (chunk) => {
            this.generateTerrain(chunk);
        });
    },
    generateTerrain(chunk) {
        // Populate the 32x32 grid with noise data
    }
};

6. React & PixiJS Communication Bridge

React (State) and PixiJS (Render Loop) must remain strictly decoupled to protect performance.

They communicate entirely via a lightweight Event Bus or Command Pattern: